#include "coordinate.h"
#include "longinstance2b.h"
#include "rectangle.h"
#include <vector>
#include <random>

/**
 * parent selection: roulette wheel
 * each parent generates ONLY 1 child by mutation
 * survival selection: fitness proportional
 * configurable elitism
 */
class EaToFindRectangles
{

private:
	std::vector<Coordinate> majors;
	std::vector<Coordinate> minors;

	int popSize;
	int childrenNum; 
	int eliteNum;
	int maxGeneration;
	int stopAfterNoPenaltyProgress;

	vector<vector<Rectangle>> ind; //individuals We keep the children at the end of this vector.
	vector<long int> penalty;
	vector<int> eliteIndex;
	//vector<int> rank; //rank[i] tells the index to the ith best individual in the ind vector.

	int tournamentSize;

	std::default_random_engine randomLongGenerator;

	EaToFindRectangles();
	EaToFindRectangles(const EaToFindRectangles& other);
	
	/**
	 * The number of rectangles in each individual is between 1 to minors.
	 */
	void initializeRandom();

	void initializeAllToOneBigRectangle();

	///Updates the penalty of ind[0] to ind[popSize] only.
	void updateIndPenalty();

	/**
	 * It is called when there are only popSize inds in the population (no children yet).
	 */
	void updateEliteIndexVector();

	void makeChildren();
	void mutate(vector<Rectangle>& thisInd);
	void mutate_mergeTwo(vector<Rectangle>& thisInd);
	void mutate_splitAny(vector<Rectangle>& thisInd);
	void mutate_splitThis_horizontal(vector<Rectangle>& thisInd, int indexToSplit);
	void mutate_splitThis_vertical(vector<Rectangle>& thisInd, int indexToSplit);

	void updateBestLastPenalty(long int* bestPenaltyArray, int arraySize);

	void advancePopulationToNextGen();
	//void updateRankVector();
	

public:
	EaToFindRectangles(LongInstance& majorLI, LongInstance& minorLI);
	void setParameters ( int popsize, int generationNum, int stopNoPenaltyProgress, int tournamentSize, int parentPoolSize, int elites);
	vector<Rectangle> runAndReturnResult(void);
};
